package usermanager

import (
	"context"
	"errors"
	"sync"
	"time"

	"dev.ixmxm.top/rms/boot"
	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/config"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/utils/function"
	"dev.ixmxm.top/rms/utils/log"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

func New(db *boot.MongoDB) *UserManager {
	rm := &UserManager{db: db, Userauthor: &UserauthorManage{}}
	rm.TcpConnect()
	return rm
}

type UserManager struct {
	db           *boot.MongoDB
	userLock     sync.Mutex
	SystemConfig *model.SystemConfig //系统配置(缓存),不可直接赋值保存，调用SaveSystemConfigToCache保存
	Userauthor   *UserauthorManage
}

func (m *UserManager) TcpConnect() {
	if config.Conf.AuthorModel.Switch == 1 {
		go func() {
			m.ConnectServer(context.Background())
		}()
	}
}

func (m *UserManager) GetAllUserFromDB(ctx context.Context) ([]model.User, codes.Code) {
	users := make([]model.User, 0)
	res, err := m.db.Collection(ctx, model.User{}.TableName()).Find(ctx, bson.M{})
	if err != nil {
		log.ErrorfWithContext(ctx, "get all user from db error:%s", err.Error())
		return nil, codes.ErrDatabase.Wrap(err)
	}
	if errBind := res.All(ctx, &users); errBind != nil {
		log.ErrorfWithContext(ctx, "bind all charge sites error:%s", errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return users, nil
}

//根据用户帐号查询用户信息
func (m *UserManager) GetOneUserFromDB(ctx context.Context, account string) (*model.User, codes.Code) {
	m.userLock.Lock()
	defer m.userLock.Unlock()
	dbRes := m.db.Collection(ctx, model.User{}.TableName()).FindOne(ctx, bson.M{"account": account})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "get one user(GetOneUserFromDB):%d from db error:%s", account, dbRes.Err().Error())
		return nil, codes.ErrDatabase.Wrap(dbRes.Err())
	}
	if errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "get one user(GetOneUserFromDB):%d from db error:%s", account, dbRes.Err().Error())
		return nil, nil
	}
	user1 := new(model.User)
	if errBind := dbRes.Decode(user1); errBind != nil {
		log.ErrorfWithContext(ctx, "bind User account:%s error:%s", account, errBind.Error())
		return nil, codes.ErrDatabase.Wrap(errBind)
	}
	return user1, nil

}

//AddRMSLogToDB 添加rms日志到数据库
func (m *UserManager) AddUserToDB(ctx context.Context, user *model.User) codes.Code {
	m.userLock.Lock()
	defer m.userLock.Unlock()
	//先验证是否具有相同帐号
	dbRes := m.db.Collection(ctx, model.User{}.TableName()).FindOne(ctx, bson.M{"account": user.Account})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "get user(AddUserToDB):%d from db error:%s", user.Account, dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}
	canAdd := false
	if dbRes.Err() != nil && errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		//log.Errorf("can not find task:%d",id)
		canAdd = true
	}

	if !canAdd {
		log.Errorf("can not add user:%d", user.Account)
		return codes.ErrExitUserAccount
	}

	//新增用户
	user.CreateTime = time.Now().UTC()
	user.UpdateTime = time.Now().UTC()
	_, errInsert := m.db.Collection(ctx, user.TableName()).InsertOne(ctx, user)
	if errInsert != nil {
		log.ErrorfWithContext(ctx, "insert rms user to db error:%s", errInsert.Error())
		return codes.ErrDatabase.Wrap(errInsert)
	}
	return nil
}

//AddRobotLogToDB 添加robot日志到数据库
func (m *UserManager) UpdateUserToDB(ctx context.Context, user *model.User) codes.Code {
	m.userLock.Lock()
	defer m.userLock.Unlock()
	user.UpdateTime = time.Now()
	//更新
	dbRes := m.db.Collection(ctx, user.TableName()).FindOneAndReplace(ctx, bson.M{"account": user.Account}, user, &options.FindOneAndReplaceOptions{Upsert: function.BoolPtr(true)})
	if dbRes.Err() != nil && !errors.Is(dbRes.Err(), mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "fupdate user from db error:%s", dbRes.Err().Error())
		return codes.ErrDatabase.Wrap(dbRes.Err())
	}
	return nil
}

//GetRMSLogsForPageFromDB 从数据库获得rms日志，并分页
func (m *UserManager) DeleteUserToDB(ctx context.Context, account string) codes.Code {
	m.userLock.Lock()
	defer m.userLock.Unlock()
	_, err := m.db.Collection(ctx, model.User{}.TableName()).DeleteOne(ctx, bson.M{"account": account})
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		log.ErrorfWithContext(ctx, "delete user by account from db error:%s", err.Error())
		return codes.ErrDatabase.Wrap(err)
	}
	return nil
}
